package com.xu.cloud.common.process;

import com.xu.cloud.common.aop.ProcessorPointcut;
import com.xu.cloud.common.pojo.http.req.BaseRequest;
import com.xu.cloud.common.pojo.http.resp.BaseResponse;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.autoproxy.AbstractBeanFactoryAwareAdvisingPostProcessor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.lang.Nullable;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 业务执行aop拦截器
 *
 * @author xuguan
 * @since 2024/9/24
 */
@Configuration
public class ProcessorAdvisingBeanPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor {
    @Autowired(required = false)
    private List<IHandler> handlers;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        super.setBeanFactory(beanFactory);
        this.advisor = new DefaultPointcutAdvisor(new ProcessorPointcut(), new ProcessorMethodInterceptor(handlers));
    }

    private static class ProcessorMethodInterceptor implements MethodInterceptor {
        @Nullable
        private final List<IHandler> handlers;

        private ProcessorMethodInterceptor(@Nullable List<IHandler> handlers) {
            this.handlers = handlers;
        }

        @Override
        public Object invoke(MethodInvocation methodInvocation) throws Throwable {
            final Object[] args = methodInvocation.getArguments();
            BaseRequest request = (BaseRequest) args[0];
            final List<IHandler> realHandlers = getRealHandlers(request);

            Exception e = null;
            BaseResponse response = null;
            try {
                for (int i = 0; i < realHandlers.size(); i++) {
                    realHandlers.get(i).preProcess(request);
                }

                response = (BaseResponse) methodInvocation.proceed();

                for (int i = realHandlers.size() - 1; i >= 0; i--) {
                    realHandlers.get(i).postProcess(request, response);
                }

                return response;
            } catch (Throwable th) {
                if (th instanceof Exception) {
                    e = (Exception) th;
                }
                throw th;
            } finally {
                for (int i = realHandlers.size() - 1; i >= 0; i--) {
                    realHandlers.get(i).completeProcess(request, response, e);
                }
            }
        }

        private List<IHandler> getRealHandlers(BaseRequest request) {
            // 无拦截器
            if (handlers == null) {
                return new ArrayList<>();
            }
            // 按照Order注解排序
            AnnotationAwareOrderComparator.sort(handlers);
            return handlers.stream()
                    .filter(handler -> handler.needHandle(request))
                    .collect(Collectors.toList());
        }
    }
}
